Fix rangeslider "fixed" rangemode using placeholder range of autoranged counter axis - #7967
Conversation
CAOShurong
left a comment
There was a problem hiding this comment.
Exact-head verification review (diff walked against upstream/main ba10ef79d, PR head 11f79e4f).
Root cause - confirmed
src/plots/cartesian/set_convert.js(~L492) falls back toconstants.DFLTRANGEY = [-1, 4]when ayaxis has no valid range at supply-defaults time.src/components/rangeslider/defaults.js(~L67-72) then defaults the counter-axisrangeslider.yaxis.rangeoffyAxOut.range.slice()for anyrangemode !== 'match'- so forfixedon an autoranged counter axis, the slider range starts life as the[-1, 4]placeholder.doAutoRange(src/plots/cartesian/autorange.js~L401) only refreshesaxeRangeOpts.rangewhenrangemode === 'auto', so the stale placeholder survives to draw; the opposite-axis masks then shade everything outside the disagreement between[-1, 4]and the real data band, which is exactly the two grey bands in the screenshots.- The toggle behavior also checks out: switching
rangemodeaway and back forces a second supply-defaults pass, by which time the y axis holds its computed range, so the re-coercedfixedrange is correct.
Fix assessment
- Flagging only defaulted-from-placeholder
fixedranges (!rangemodeDflt && yAxOut.autorange) and routing them through the existing'auto'branch indoAutoRangeis a minimal fix with no schema change. Delete-on-consume gives "resolve once, then stays put", which matches thefixedcontract: later autorange changes correctly leave the slider alone (covered by the restyle step in the new test). - Internal-key hygiene checked: the flag lives on the full-layout container, and by the time
anchorAx._input.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts)copies state back toward user input the flag has already been deleted, so nothing leaks intogd.layout. FreshnewPlotcalls start from clean containers, so no stale-flag path there either.
Nits (non-blocking)
- The new test locks in the numeric behavior but not the internal-key claim from the PR description. Cheap insurance: assert
'_rangeDfltFromAutorangedAx' in gd._fullLayout.xaxis.rangeslider.yaxisisfalseafter the first plot (and/or absent from the layout input). That guards against someone later moving theextendFlatcopy above thedelete. - The reported repro includes the rangemode toggle clearing the bands. A follow-up
Plotly.relayout(gd, 'xaxis.rangeslider.yaxis.rangemode', ...)round-trip asserting the slider range stays sane would pin down the second-supply-defaults path this PR deliberately leaves untouched. - Explicit-but-invalid
rangeslider.yaxis.rangetogether withfixed:rangemodeDfltstays undefined, so the flag applies and the range resolves once from autorange. I believe that is the right fallback (user asked forfixedwith an unusable range), but a line in the draftlog entry would stop future readers from mistaking it for an accident.
CI note: only the Orca security scans have run on this head so far; the jasmine suites are maintainer-gated, so the new test has not executed yet. Mergeable state verified via API at review time.
|
Hi @Guhapriya01, thanks for the PR. Could you open an issue in plotly.js corresponding to this bug, with plotly.js reproduction steps? The existing issue only covers plotly.py. That issue will also give us a place to discuss the best implementation for a fix before jumping straight to a PR. Adding an internal flag variable is one possible approach, but it's a bit of an anti-pattern and can sometimes introduce other hard-to-diagnose bugs, so I'm hesitant to sign off on that approach unless we've determined it's the only reasonable way of fixing this bug. |
Fixes plotly/plotly.py#5614
Problem
With
rangeslider.yaxis.rangemode: "fixed"and no explicit range, the slider renders two grey bands on initial load; toggling rangemode away and back clears them. The bands are the opp-axis masks, which shade the slider outside the fixed y-range — visible only when that range disagrees with the data.Cause
rangeslider/defaults.jsdefaults the fixed range offyAxOut.range. When the counter axis autoranges, that is still theDFLTRANGEY[-1, 4]placeholder at supplyDefaults time. Unlikerangemode: 'auto', nothing revisits it afterwards.Toggling works only because it forces a second supplyDefaults, by which point the axis holds its computed range.
Fix
Flag a
fixedrange defaulted off a not-yet-autoranged axis, and letdoAutoRangefill it in via the path'auto'already uses. The flag is deleted once consumed, sofixedresolves once and then stays put, and the internal key is not copied out tolayout.No schema change;
auto,match, explicit ranges and non-autoranged axes are unaffected.